package com.linkai.JUC._17_threadlocal;

import java.util.concurrent.TimeUnit;

/**
 * @Description: ThreadLocal
 *              1. ThreadLocal是Java中所提供的线程本地存储机制，可以利用该机制将数据缓存再某个线程内部，该线程可以在任意时刻，任意方法中获取缓存的数据
 *              2. ThreadLocal 底层是通过 ThreadLocalMap 来实现的，每个 Thread 对象（注意不是 ThreadLocal对象）中都存在一个
 *                 ThreadLocalMap，Map的key为ThreadLocal对象，Map的value为需要缓存的值。
 *              3. 如果在线程池中使用 ThreadLocal 会造成内存泄露，因为当 ThreadLocal 对象使用完成之后，应该要把设置的key，value，
 *                 也就是 Entry 对象进行回收，但是线程池中的线程不会回收，而线程对象是通过强应用指向 ThreadLocalMap，
 *                 ThreadLocalMap也是通过强应用指向 Entry对象，线程不被回收，Entry对象也就不会被回收，从而出现内存泄露；
 *              4. ThreadLocal经典的应用场景就是连接管理（一个线程持有一个连接，该连接对象可以在不同的方法之间进行传递，线程之间不共享同一个连接）
 *                  （1）数据库连接
 *                  （2）session管理，例如tomcat处理请求，会开启一个线程处理，此时用 ThreadLocal 来存储 Session
 *
*               https://www.jianshu.com/p/6fc3bba12f38
 * @Author: 林凯
 * @Date: 2021/11/13 15:09
 */
public class TestThreadLocal {
    public static void main(String[] args) {
        Person person = new Person();

        new Thread(new Runnable() {
            @Override
            public void run() {
                // 传入进来的“林凯”，会被缓存在当前的线程内
                person.setName("林凯");
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 从线程缓存里面中获取的
                System.out.println("线程1=======" + person.getName());
                person.remove();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                person.setName("JackLin");
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程2=======" + person.getName());
                person.remove();

            }
        }).start();

    }
}

class Person {
    // 底层原理
    // 这个 name 对象当做 ThreadLocalMap 的key，里面具体的值作为value
    private ThreadLocal<String> name = new ThreadLocal<>();
    private ThreadLocal<String> age = new ThreadLocal<>();

    public void setName(String name) {
        // 为 ThreadLocal 对象赋值
        this.name.set(name);
    }

    public String getName() {
        return this.name.get();
    }

    // 线程池中使用时，需要手动地释放对象，防止内存溢出
    public void remove() {
        this.name.remove();
    }

}
